package jp.crwdev.app.gui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.util.List; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.DefaultCellEditor; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.border.EmptyBorder; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; import jp.crwdev.app.OutputSettingParam; import jp.crwdev.app.constant.Constant; import jp.crwdev.app.container.ImageFilePreconverter; import jp.crwdev.app.container.ImageFileScanner; import jp.crwdev.app.imagefilter.OutputImageFilter; import jp.crwdev.app.interfaces.IImageFileInfoList; import jp.crwdev.app.interfaces.IImageFileScanner; import jp.crwdev.app.interfaces.IImageFileWriter; import jp.crwdev.app.interfaces.IImageFileWriter.OnProgressListener; import jp.crwdev.app.setting.ImageFilterParamSet; import jp.crwdev.app.setting.XmlWriter; import jp.crwdev.app.util.FileListDropTargetAdapter; import jp.crwdev.app.util.InifileProperty; import jp.crwdev.app.util.FileListDropTargetAdapter.OnDropFilesListener; @SuppressWarnings("serial") public class BatWorkDialog extends JDialog implements OnDropFilesListener { public static final String[] TABLE_HEADER_COLUMNS = new String[]{ "状態", "入力パス", "タイトル", "著者名", "タイトルカナ", "著者名カナ", "出力パス", "出力サイズ", "ファイル種別", "Book種別", "シリーズ名", "巻数", "シリーズ名カナ", "固定サイズ出力", }; private static final int TABLE_INDEX_STATUS = 0; private static final int TABLE_INDEX_INPUT_PATH = 1; private static final int TABLE_INDEX_TITLE = 2; private static final int TABLE_INDEX_AUTHOR = 3; private static final int TABLE_INDEX_TITLE_KANA = 4; private static final int TABLE_INDEX_AUTHOR_KANA = 5; private static final int TABLE_INDEX_OUTPUT_NAME = 6; private static final int TABLE_INDEX_IMAGESIZE = 7; private static final int TABLE_INDEX_FILETYPE = 8; private static final int TABLE_INDEX_BOOKTYPE = 9; private static final int TABLE_INDEX_SERIES_TITLE = 10; private static final int TABLE_INDEX_SERIES_NUMBER = 11; private static final int TABLE_INDEX_SERIES_TITLE_KANA = 12; private static final int TABLE_INDEX_OUTPUT_FIXED_SIZE = 13; private final JPanel contentPanel = new JPanel(); private JTable table; private JTextField textFolder; private JButton folderButton; private JButton convertButton; private boolean mIsProcessing = false; private boolean mIsCancel = false; private DefaultTableModel mTableModel = null; private Object mLock = new Object(); private IImageFileWriter mFileWriter = null; private MainFrame mParent; public BatWorkDialog(JFrame mParentFrame){ super(mParentFrame, true); initialize(); addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e) { System.out.println("windowClosing"); if(mIsProcessing){ JOptionPane.showMessageDialog(BatWorkDialog.this, "処理中です。"); } else{ dispose(); } } }); new DropTarget(this, new FileListDropTargetAdapter(this)); setTitle("一括変換"); setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); setVisible(true); } public void initialize(){ setBounds(100, 100, 450, 300); getContentPane().setLayout(new BorderLayout()); contentPanel.setBorder(new EmptyBorder(3, 3, 3, 3)); getContentPane().add(contentPanel, BorderLayout.CENTER); contentPanel.setLayout(new BorderLayout()); table = new JTable(); JScrollPane scroll = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); contentPanel.add(scroll); { JPanel buttonPane = new JPanel(); getContentPane().add(buttonPane, BorderLayout.SOUTH); buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); { textFolder = new JTextField(); buttonPane.add(textFolder); textFolder.setColumns(10); } { folderButton = new JButton("出力フォルダ"); buttonPane.add(folderButton); folderButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { showOutputFolderDialog(); } }); } { convertButton = new JButton("変換"); buttonPane.add(convertButton); convertButton.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent arg0) { if(mIsProcessing){ cancelConvert(); }else{ beginConvert(); } } }); } } mTableModel = new DefaultTableModel(TABLE_HEADER_COLUMNS, 0){ @Override public boolean isCellEditable(int row, int column) { return (column > 1); // 0,1カラム目の編集禁止 } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Class getColumnClass(int col){ return getValueAt(0, col).getClass(); } }; table.setModel(mTableModel); for(int i=0; i<TABLE_HEADER_COLUMNS.length; i++){ TableColumn col = table.getColumnModel().getColumn( i ); col.setMinWidth(50); } table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); // ImageSize Column List<String> imageSizeList = InifileProperty.getInstance().getImageSizeList(); String[] imageSizeType = new String[imageSizeList.size()+1]; int i=0; for(String size : imageSizeList){ imageSizeType[i++] = size; } imageSizeType[i] = "リサイズ無し"; JComboBox imageSizeBox = new JComboBox(imageSizeType); TableColumn imageSizeColum = table.getColumnModel().getColumn(TABLE_INDEX_IMAGESIZE); imageSizeColum.setCellEditor(new DefaultCellEditor(imageSizeBox)); // FileType Column JComboBox fileTypeBox = new JComboBox(new String[] { "zip", "epub", "pdf", "folder" }); fileTypeBox.setBorder(BorderFactory.createEmptyBorder()); TableColumn fileTypeColum = table.getColumnModel().getColumn(TABLE_INDEX_FILETYPE); fileTypeColum.setCellEditor(new DefaultCellEditor(fileTypeBox)); // BookType Column JComboBox bookTypeBox = new JComboBox(new String[] { "book", "magazin", "comic" }); bookTypeBox.setBorder(BorderFactory.createEmptyBorder()); TableColumn bookTypeColum = table.getColumnModel().getColumn(TABLE_INDEX_BOOKTYPE); bookTypeColum.setCellEditor(new DefaultCellEditor(bookTypeBox)); mTableModel.addTableModelListener(new TableModelListener(){ @Override public void tableChanged(TableModelEvent event) { int row = event.getLastRow(); int col = event.getColumn(); if(row >= 0 && col >= 0){ if(col != TABLE_INDEX_OUTPUT_FIXED_SIZE){ String value = (String)mTableModel.getValueAt(row, col); onTableCellChanged(row, col, value); } } } }); } private void onTableCellChanged(int row, int col, String value){ if(col == TABLE_INDEX_FILETYPE){ if(!value.equalsIgnoreCase("folder")){ String filename = (String)mTableModel.getValueAt(row, TABLE_INDEX_OUTPUT_NAME); int dotIndex = filename.lastIndexOf("."); if(dotIndex >= 0){ filename = filename.substring(0, dotIndex); } filename += "." + value; mTableModel.setValueAt(filename, row, TABLE_INDEX_OUTPUT_NAME); } } else if(col == TABLE_INDEX_SERIES_NUMBER){ if(!value.isEmpty()){ try{ Integer.parseInt(value); }catch(NumberFormatException e){ mTableModel.setValueAt("", row, TABLE_INDEX_SERIES_NUMBER); } } } } private void showOutputFolderDialog(){ JFileChooser filechooser = new JFileChooser(); filechooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); File defaultFolder = new File(InifileProperty.getInstance().getOutputFolder()); if(defaultFolder.exists() && defaultFolder.isDirectory()){ filechooser.setSelectedFile(defaultFolder); } int selected = filechooser.showOpenDialog(mParent); if(selected == JFileChooser.APPROVE_OPTION){ File file = filechooser.getSelectedFile(); textFolder.setText(file.getAbsolutePath()); InifileProperty.getInstance().setOutputFolder(file.getAbsolutePath()); } } public void addData(String contentPath, OutputSettingParam output){ Object[] record = createRecord(contentPath, output); mTableModel.addRow(record); } private Object[] createRecord(String contentPath, OutputSettingParam output){ // private static final int TABLE_INDEX_INPUT_PATH = 0; // private static final int TABLE_INDEX_TITLE = 1; // private static final int TABLE_INDEX_AUTHOR = 2; // private static final int TABLE_INDEX_TITLE_KANA = 3; // private static final int TABLE_INDEX_AUTHOR_KANA = 4; // private static final int TABLE_INDEX_OUTPUT_PATH = 5; // private static final int TABLE_INDEX_IMAGESIZE = 6; // private static final int TABLE_INDEX_FILETYPE = 7; // private static final int TABLE_INDEX_BOOKTYPE = 8; // String title = output.getTitle(); String titleKana = output.getTitleKana(); String author = output.getAuthor(); String authorKana = output.getAuthorKana(); String filename = output.getOutputFileName(null); Dimension size = output.getImageSize(); String imagesize = size.width + "x" + size.height; String fileType = output.getFileType(); String bookType = output.getEpubType(); String seriesTitle = output.getSeriesTitle(); String seriesNumber = Integer.toString(output.getSeriesNumber()); String seriesTitleKana = output.getSeriesTitleKana(); Boolean fixedSize = new Boolean(output.isFixedSize()); return new Object[]{"未変換", contentPath, title, author, titleKana, authorKana, filename, imagesize, fileType, bookType, seriesTitle, seriesNumber, seriesTitleKana, fixedSize}; } @Override public void onDrop(List<String> paths) { XmlWriter xml = new XmlWriter(); for(int i=0; i<paths.size(); i++){ File settingFile = Constant.getSettingFile(new File(paths.get(i))); if(settingFile != null){ if(xml.openLoadSettingFile(settingFile.getAbsolutePath())){ OutputSettingParam output = new OutputSettingParam("","","",""); xml.loadSetting(output, null, null); addData(paths.get(i), output); } } } } private void beginConvert(){ String outputFolder = textFolder.getText(); if(outputFolder.isEmpty()){ JOptionPane.showMessageDialog(this, "出力先フォルダが指定されていません。"); return; } File outFolder = new File(outputFolder); if(!outFolder.exists() || !outFolder.isDirectory()){ JOptionPane.showMessageDialog(this, "出力先にはフォルダを指定してください。"); return; } int count = mTableModel.getRowCount(); if(count <= 0){ return; } table.clearSelection(); mIsProcessing = true; mIsCancel = false; textFolder.setEnabled(false); folderButton.setEnabled(false); convertButton.setText("キャンセル"); Thread thread = new Thread(){ public void run(){ String outputFolder = textFolder.getText(); int count = mTableModel.getRowCount(); for(int i=0; i<count; i++){ try { doConvert(outputFolder, i); }catch(Exception e){ e.printStackTrace(); } if(mIsCancel){ break; } } textFolder.setEnabled(true); folderButton.setEnabled(true); convertButton.setText("変換"); mIsProcessing = false; } }; thread.setPriority(3); thread.start(); } private void cancelConvert(){ mIsCancel = true; synchronized(mLock){ if(mFileWriter != null){ mFileWriter.cancel(); } } } private String getContentPath(int index){ if(index < 0 || mTableModel.getRowCount() <= index){ return null; } String contentPath = (String)mTableModel.getValueAt(index, TABLE_INDEX_INPUT_PATH); return contentPath; } private OutputSettingParam getOutputSettingParam(int index){ if(index < 0 || mTableModel.getRowCount() <= index){ return null; } try { String title = (String)mTableModel.getValueAt(index, TABLE_INDEX_TITLE); String titleKana = (String)mTableModel.getValueAt(index, TABLE_INDEX_TITLE_KANA); String author = (String)mTableModel.getValueAt(index, TABLE_INDEX_AUTHOR); String authorKana = (String)mTableModel.getValueAt(index, TABLE_INDEX_AUTHOR_KANA); String filename = (String)mTableModel.getValueAt(index, TABLE_INDEX_OUTPUT_NAME); String imageSize = (String)mTableModel.getValueAt(index, TABLE_INDEX_IMAGESIZE); String fileType = (String)mTableModel.getValueAt(index, TABLE_INDEX_FILETYPE); String bookType = (String)mTableModel.getValueAt(index, TABLE_INDEX_BOOKTYPE); String seriesTitle = (String)mTableModel.getValueAt(index, TABLE_INDEX_SERIES_TITLE); String seriesNumber = (String)mTableModel.getValueAt(index, TABLE_INDEX_SERIES_NUMBER); String seriesTitleKana = (String)mTableModel.getValueAt(index, TABLE_INDEX_SERIES_TITLE_KANA); Boolean fixedSize = (Boolean)mTableModel.getValueAt(index, TABLE_INDEX_OUTPUT_FIXED_SIZE); OutputSettingParam param = new OutputSettingParam("", fileType, bookType, imageSize); param.setTitle(title); param.setTitleKana(titleKana); param.setAuthor(author); param.setAuthorKana(authorKana); param.setOutputFileName(filename); param.setSeriesTitle(seriesTitle); if(!seriesNumber.isEmpty()){ param.setSeriesNumber(Integer.parseInt(seriesNumber)); } param.setSeriesTitleKana(seriesTitleKana); param.setFixedSize(fixedSize); return param; }catch(Exception e){ e.printStackTrace(); } return null; } private void updateStatus(int index, String status){ if(index < 0 || mTableModel.getRowCount() <= index){ return; } mTableModel.setValueAt(status, index, TABLE_INDEX_STATUS); } private void doConvert(String outputFolder, int index){ String contentPath = getContentPath(index); OutputSettingParam output = getOutputSettingParam(index); output.setOutputPath(outputFolder); updateStatus(index, "変換中"); IImageFileScanner scanner = ImageFileScanner.getFileScanner(contentPath); IImageFileInfoList list = scanner.getImageFileInfoList(); File settingFile = Constant.getSettingFile(new File(contentPath)); if(settingFile == null){ updateStatus(index, "失敗:設定ファイルが見つかりません"); return; } list.sort(); //ImageFilterParam param = null; ImageFilterParamSet params = new ImageFilterParamSet(); if(settingFile.exists()){ XmlWriter loader = new XmlWriter(); loader.openLoadSettingFile(settingFile.getAbsolutePath()); // listに変更を反映する loader.loadSetting(null, params, list); } params.setPreview(false); // 出力サイズを設定 Dimension size = output.getImageSize(); if(size == null || (size.width == 0 || size.height == 0)){ params.setResize(false); }else{ params.setResize(true); params.setResizeDimension(size); } if(output.isFixedSize()){ // 固定出力サイズチェック OutputImageFilter preconvertFilter = new OutputImageFilter(params, false); ImageFilePreconverter checker = new ImageFilePreconverter(preconvertFilter); checker.write(list, null); Dimension unionSize = checker.getUnionSize(); params.setFixedSize(unionSize); } // 基本出力フィルタを生成 OutputImageFilter imageFilter = new OutputImageFilter(params, output.isFixedSize()); // 出力設定からImageFileWriterを生成 IImageFileWriter writer = output.getImageFileWriter(); writer.setImageFilter(imageFilter); // 出力ファイル(フォルダ)パスを作成 File dir = new File(output.getFinalOutputPath()); File file = new File(dir.getAbsolutePath(), output.getOutputFileName(writer.getSuffix())); if(!dir.exists()){ if(!dir.mkdirs()){ updateStatus(index, "失敗:出力フォルダを作成できませんでした"); return; //throw new Exception("can't create output folder."); } } // 出力ファイル(フォルダ)オープン if(writer.open(file.getAbsolutePath())){ synchronized(mLock){ mFileWriter = writer; // ここからCancel可能 } // 出力処理開始 final int rowIndex = index; boolean result = writer.write(list, new OnProgressListener(){ private int preProgress = 0; @Override public void onProgress(int progress, String message) { int val = (progress / 10) * 10; if(val != preProgress){ preProgress = val; if(message == null){ message = progress + "%"; } updateStatus(rowIndex, message); } } }); // 出力終了 synchronized(mLock){ mFileWriter = null; } writer.close(); if(mIsCancel){ updateStatus(index, "キャンセル"); }else{ if(result){ updateStatus(index, "変換済み"); }else{ updateStatus(index, "変換失敗"); } } } else{ updateStatus(index, "失敗:出力先を開けませんでした"); } scanner.close(); scanner = null; } }